package me.flyray.bsin.server.utils;

import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.plexpt.chatgpt.ChatGPT;
import com.plexpt.chatgpt.entity.chat.ChatCompletion;
import com.plexpt.chatgpt.entity.chat.ChatCompletionResponse;
import com.plexpt.chatgpt.entity.chat.Message;
import com.plexpt.chatgpt.util.Proxys;
import lombok.extern.log4j.Log4j;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.flyray.bsin.cache.BsinCacheProvider;
import me.flyray.bsin.exception.BusinessException;
import me.flyray.bsin.server.config.ChatGPTConfiguration;
import me.flyray.bsin.server.domain.TenantWxPlatformRole;
//import me.flyray.bsin.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.Proxy;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author leonad
 * ClassName:OpenAIAPI.java
 * date:2023-04-24 16:49
 * Description:
 */
//@UtilityClass
@Log4j
@Service
public class OpenAI {
    private static ConcurrentHashMap<String, ChatGPT> concurrentChatGPTHashMap = new ConcurrentHashMap();


    @Autowired
    private BsinCacheProvider bsinCacheProvider;

//    stringRedisTemplate.opsForValue().set("student",JSON.toJSONString(students));
//    // 获取student对象
//    String student = stringRedisTemplate.opsForValue().get("student");

//    private ChatContextHolder chatContextHolder;
//    private Proxy proxy = null;
//    private ChatGPT chatGPT = null;
//    private String chatEndpoint = "http://nginx.web-framework-1qoh.1045995386668294.us-west-1.fc.devsapp.net/v1/chat/completions";
//    private String mirrorApiKey = "Bearer dm5NkmdosotYC1BZ9ViAT3BlbkFJBPixz5DkZvHom80pM0lJ";

//    public OpenAI() {
//        mirrorApiKey = "Bearer " + chatGPTConfiguration.getKey().get(0);
//        chatEndpoint = chatGPTConfiguration.toString();
//        chatContextHolder = new ChatContextHolder();
//        Proxy proxy = Proxys.http(chatGPTConfiguration.getProxyServer(), chatGPTConfiguration.getProxyPort());
//        this.chatGPT = ChatGPT.builder()
//                .apiKey(chatGPTConfiguration.getKey().get(0))
//                .timeout(900)
//                .proxy(proxy)
//                .apiHost(chatGPTConfiguration.getUrl())
//                .build()
//                .init();
//        chatGPT = ChatGPT.builder()
//                .apiKeyList(
//                        // 从数据库或其他地方取出多个KEY
//                        Arrays.asList("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",
//                                "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",
//                                "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",
//                                "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",
//                                ))
//                .timeout(900)
//                .proxy(proxy)
//                .apiHost("https://api.openai.com/") //代理地址
//                .build()
//                .init();
//
//        chatGPT = ChatGPT.builder()
//                .apiKeyList(
//                        // 从数据库或其他地方取出多个KEY
//                        Arrays.asList(
////                                environment.getProperty("chatgpt.key[0]"),
////                                environment.getProperty("chatgpt.key[1]"),
//                                environment.getProperty("chatgpt.key[2]"),
//                                environment.getProperty("chatgpt.key[3]")
//                        ))
//                .timeout(900)
//                .proxy(proxy)
//                .apiHost(environment.getProperty("chatgpt.url")) //代理地址
//                .build()
//                .init();
//
//        CreditGrantsResponse response = chatGPT.creditGrants();
//        log.info("余额：{}", response.getTotalAvailable());
//    }

    /**
     * 聊天端点 楼主提供国内免费调用ChatGPT站点，不需要开梯子，请求稍微慢一点，请耐心等待哦
     *
     * @param prompt 内容
     * @return {@link String}
     */
    public String mirrorChat(String prompt, ChatGPTConfiguration chatGPTConfiguration) {
        String chatEndpoint = "Bearer " + chatGPTConfiguration.getKey();
        String mirrorApiKey = chatGPTConfiguration.getMirrorUrl();
        Map<String, Object> paramMap = new HashMap<>();
//        paramMap.put("model", "gpt-3.5-turbo");
        paramMap.put("model", chatGPTConfiguration.getModel());
        List<Map<String, String>> dataList = new ArrayList<>();
        dataList.add(new HashMap<String, String>() {{
            put("role", "user");
            put("content", prompt);
        }});
        paramMap.put("messages", dataList);
        JSONObject message = null;
        try {
            String body = HttpRequest.post(chatEndpoint)
                    .header("Authorization", mirrorApiKey)
                    .header("Content-Type", "application/json")
                    .body(JsonUtils.toJson(paramMap))
                    .execute()
                    .body();
            JSONObject jsonObject = JSONUtil.parseObj(body);
            JSONArray choices = jsonObject.getJSONArray("choices");
            JSONObject result = choices.get(0, JSONObject.class, Boolean.TRUE);
            message = result.getJSONObject("message");
        } catch (Exception e) {
            return "欢迎加入s11eDao，当前环境出现问题!";
        }
        return message.getStr("content");
    }

//    /**
//     * 发送消息
//     *
//     * @param prompt 内容
//     * @return {@link String}
//     */
//    public String chat(String system, String prompt) {
////        String role = new String("你是一个在线红娘，你的名字叫恋AI脑，你18岁，你是女孩");
////        String maxtoken = environment.getProperty("chatgpt.temperature");
////        String temperature = environment.getProperty("chatgpt.temperature");
//        //        Message system = Message.ofSystem("你是一个在线红娘，你的名字叫恋AI脑，你18岁，你是女孩。请根据我的回答同时再向我提出一个问题，当询问我8次后，可以了解我的性别，所在城市，职业，年龄，以及我对另一半年龄、工作、地点、收入的要求，你的每次提问如果没有得到有效的回答，要再次提问，直到问到有效答案为止。每次你的问题需要我来回答，你不要自问自答。当向我询问8次以后，才对我的性格特点进行分析，分析要做深度延展，从性格色彩，星座特点，爱情观，世界观等维度进行分析并为我建议另一半的画像，包括另一半的星座，爱情观，世界观等。在最后的最后问我要一张生活照和手机号，以便帮更好的做匹配，并加一句话，我们将从单身会员库为您匹配最合适的另一半，请稍做等待，您也可以添加人工速配官微信：metaAI2023，进行咨询。在你问我第一个问题前要说明你问我问题的目的，现在你可以开始向我问第一个问题了。");
////        Message system = Message.ofSystem("你是一个在线红娘，你的名字叫恋AI脑");
//        Message system_ = Message.ofSystem("你是一个在线红娘，你的名字叫恋AI脑");
//        Message message = Message.of(prompt);
//
////        chatContextHolder.add(wxMessage.getFromUser(), message.getContent());
////        List<Message> listMessage = chatContextHolder.get(wxMessage.getFromUser());
////        ChatCompletion chatCompletion = ChatCompletion.builder()
////                .model(ChatCompletion.Model.GPT_3_5_TURBO.getName())
////                .messages(Arrays.asList(system, message))
////                .maxTokens(Integer.valueOf(chatGPTConfiguration.getMaxToken()))
////                .temperature(chatGPTConfiguration.getTemperature())
////                .build();
////        ChatCompletionResponse response = chatGPT.chatCompletion(chatCompletion);
////        Message res = response.getChoices().get(0).getMessage();
////        chatContextHolder.add(wxMessage.getFromUser(), res.getContent());
//        return null;
//    }

    private ChatGPT getChatGPT(ChatGPTConfiguration chatGPTConfiguration) {

        ChatGPT chatGPT;
        chatGPT = (ChatGPT) concurrentChatGPTHashMap.get(chatGPTConfiguration.getKey());
        if (null != chatGPT) {
            return chatGPT;
        }
        // 使用代理访问openAI API
//        chatGPTConfiguration.setProxyEnable(true);
        if (chatGPTConfiguration.isProxyEnable() && !StringUtils.isEmpty(chatGPTConfiguration.getProxyServer())) {
            Proxy proxy = Proxys.http(chatGPTConfiguration.getProxyServer(), chatGPTConfiguration.getProxyPort());
            if (chatGPTConfiguration.getKeyList().size() == 1) {
                chatGPT = ChatGPT.builder()
                        .apiKey(chatGPTConfiguration.getKeyList().get(0))
                        .timeout(900)
                        .proxy(proxy)
                        .apiHost(chatGPTConfiguration.getUrl())
                        .build()
                        .init();
            } else if (chatGPTConfiguration.getKeyList().size() > 1) {
                chatGPT = ChatGPT.builder()
                        .apiKeyList(chatGPTConfiguration.getKeyList())
                        .timeout(900)
                        .proxy(proxy)
                        .apiHost(chatGPTConfiguration.getUrl())
                        .build()
                        .init();
            } else {
                throw new BusinessException("100000", "cant found openAi key...");
            }
        } else {
            if (chatGPTConfiguration.getKeyList().size() == 1) {
                chatGPT = ChatGPT.builder()
                        .apiKey(chatGPTConfiguration.getKey())
                        .timeout(900)
                        .apiHost(chatGPTConfiguration.getUrl())
                        .build()
                        .init();
            } else if (chatGPTConfiguration.getKeyList().size() > 1) {
                chatGPT = ChatGPT.builder()
                        .apiKeyList(chatGPTConfiguration.getKeyList())
                        .timeout(900)
                        .apiHost(chatGPTConfiguration.getUrl())
                        .build()
                        .init();
            } else {
                throw new BusinessException("100000", "cant found openAi key...");
            }
        }
        return chatGPT;

    }

    /**
     * 发送消息
     *
     * @param wxMessage
     * @return {@link Message}
     */
    public Message chat(WxMpXmlMessage wxMessage, ChatGPTConfiguration chatGPTConfiguration, TenantWxPlatformRole
            wxmpRole) {
        ChatGPT chatGPT = getChatGPT(chatGPTConfiguration);
        List<Message> requestMessages = new ArrayList<Message>();
        //第一次调用,且启用系统角色设置
        if (!bsinCacheProvider.exist(wxMessage.getFromUser() + "Context") && chatGPTConfiguration.isSystemRoleEnable() && !StringUtils.isEmpty(chatGPTConfiguration.getSystemContent())) {
            Message systemMessage = new Message(Message.Role.SYSTEM.getValue(), wxmpRole.getContent());
            requestMessages.add(systemMessage);
        } else if (bsinCacheProvider.exist(wxMessage.getFromUser() + "Context")) {
            requestMessages = bsinCacheProvider.getList(wxMessage.getFromUser() + "Context", Message.class);
        }
        // user prompt
        Message userMessage = new Message(Message.Role.USER.getValue(), wxMessage.getContent());
        requestMessages.add(userMessage);
        int requestMessagesize = requestMessages.size();
        if (requestMessages.size() > chatGPTConfiguration.getContextLimitNum()) {
            int remove_index = 0;
            if (chatGPTConfiguration.isSystemRoleEnable() && !StringUtils.isEmpty(chatGPTConfiguration.getSystemContent())) {
                remove_index = 1;
            }
            for (int i = 0; i < (requestMessagesize - chatGPTConfiguration.getContextLimitNum()); i++) {
                requestMessages.remove(remove_index);
            }
        }
        System.out.println("requestMessage szie: " + requestMessages.size());
        System.out.println("requestMessage: " + requestMessages.toString());
        try {
            ChatCompletion chatCompletion = ChatCompletion.builder()
                    .model(ChatCompletion.Model.GPT_3_5_TURBO_0301.getName())
                    .messages(requestMessages)
                    .maxTokens(Integer.valueOf(chatGPTConfiguration.getMaxToken()))
                    .temperature(chatGPTConfiguration.getTemperature())
                    .build();
            ChatCompletionResponse response = chatGPT.chatCompletion(chatCompletion);
            Message assistanceMessage = response.getChoices().get(0).getMessage();
            System.out.println("ChatCompletionResponse： " + response.toString());
            requestMessages.add(assistanceMessage);
            bsinCacheProvider.setListEx(wxMessage.getFromUser() + "Context", requestMessages, chatGPTConfiguration.getContextExpire());
            System.out.println("chatGPT response: " + assistanceMessage.toString());
            return assistanceMessage;
        } catch (Exception e) {
            e.printStackTrace();
            return Message.builder().content(chatGPTConfiguration.getExceptionResponse()).build();
        }
    }

    /**
     * 发送消息
     *
     * @param wxMessage
     * @return {@link ChatCompletionResponse}
     */
    public ChatCompletionResponse weChatCompletionResponse(WxMpXmlMessage wxMessage, ChatGPTConfiguration chatGPTConfiguration, TenantWxPlatformRole
            wxmpRole) {
        ChatGPT chatGPT = getChatGPT(chatGPTConfiguration);
        List<Message> requestMessages = new ArrayList<Message>();
        //第一次调用,且启用系统角色设置
        if (!bsinCacheProvider.exist(wxMessage.getFromUser() + "Context") && chatGPTConfiguration.isSystemRoleEnable() && !StringUtils.isEmpty(chatGPTConfiguration.getSystemContent())) {
            Message systemMessage = new Message(Message.Role.SYSTEM.getValue(), wxmpRole.getContent());
            requestMessages.add(systemMessage);
        } else if (bsinCacheProvider.exist(wxMessage.getFromUser() + "Context")) {
            requestMessages = bsinCacheProvider.getList(wxMessage.getFromUser() + "Context", Message.class);
        }
        // user prompt
        Message userMessage = new Message(Message.Role.USER.getValue(), wxMessage.getContent());
        requestMessages.add(userMessage);
        int requestMessagesize = requestMessages.size();
        if (requestMessages.size() > chatGPTConfiguration.getContextLimitNum()) {
            int remove_index = 0;
            if (chatGPTConfiguration.isSystemRoleEnable() && !StringUtils.isEmpty(chatGPTConfiguration.getSystemContent())) {
                remove_index = 1;
            }
            for (int i = 0; i < (requestMessagesize - chatGPTConfiguration.getContextLimitNum()); i++) {
                requestMessages.remove(remove_index);
            }
        }
        System.out.println("requestMessage szie: " + requestMessages.size());
        System.out.println("requestMessage: " + requestMessages.toString());
        try {
            ChatCompletion chatCompletion = ChatCompletion.builder()
                    .model(ChatCompletion.Model.GPT_3_5_TURBO_0301.getName())
                    .messages(requestMessages)
                    .maxTokens(Integer.valueOf(chatGPTConfiguration.getMaxToken()))
                    .temperature(chatGPTConfiguration.getTemperature())
                    .build();
            ChatCompletionResponse response = chatGPT.chatCompletion(chatCompletion);
            Message assistanceMessage = response.getChoices().get(0).getMessage();
            System.out.println("ChatCompletionResponse： " + response.toString());
            requestMessages.add(assistanceMessage);
            bsinCacheProvider.setListEx(wxMessage.getFromUser() + "Context", requestMessages, chatGPTConfiguration.getContextExpire());
            System.out.println("chatGPT response: " + assistanceMessage.toString());
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @param
     * @return {@link ChatCompletionResponse}
     */
    public ChatCompletionResponse chatCompletion(ChatGPTConfiguration chatGPTConfiguration) {

        ChatGPT chatGPT = getChatGPT(chatGPTConfiguration);
        List<Message> requestMessages = new ArrayList<Message>();
        //第一次调用,且启用系统角色设置
        if (!bsinCacheProvider.exist(chatGPTConfiguration.getUserId() + "ChatCompletionContext") && chatGPTConfiguration.isSystemRoleEnable() && !StringUtils.isEmpty(chatGPTConfiguration.getSystemContent())) {
            Message systemMessage = new Message(Message.Role.SYSTEM.getValue(), chatGPTConfiguration.getSystemContent());
            requestMessages.add(systemMessage);
        } else if (bsinCacheProvider.exist(chatGPTConfiguration.getUserId() + "ChatCompletionContext")) {
            requestMessages = bsinCacheProvider.getList(chatGPTConfiguration.getUserId() + "ChatCompletionContext", Message.class);
        }
        // user prompt
        Message userMessage = new Message(Message.Role.USER.getValue(), chatGPTConfiguration.getUserContent());
        requestMessages.add(userMessage);
        int requestMessagesize = requestMessages.size();
        if (requestMessages.size() > chatGPTConfiguration.getContextLimitNum()) {
            int remove_index = 0;
            if (chatGPTConfiguration.isSystemRoleEnable() && !StringUtils.isEmpty(chatGPTConfiguration.getSystemContent())) {
                remove_index = 1;
            }
            for (int i = 0; i < (requestMessagesize - chatGPTConfiguration.getContextLimitNum()); i++) {
                requestMessages.remove(remove_index);
            }
        }
        System.out.println("chatCompletion requestMessage szie: " + requestMessages.size());
        System.out.println("chatCompletion requestMessage: " + requestMessages.toString());
        try {
            ChatCompletion chatCompletion = ChatCompletion.builder()
                    .model(ChatCompletion.Model.GPT_3_5_TURBO_0301.getName())
                    .messages(requestMessages)
                    .maxTokens(Integer.valueOf(chatGPTConfiguration.getMaxToken()))
                    .temperature(chatGPTConfiguration.getTemperature())
                    .build();
            ChatCompletionResponse response = chatGPT.chatCompletion(chatCompletion);
            Message assistanceMessage = response.getChoices().get(0).getMessage();
            System.out.println("ChatCompletionResponse： " + response.toString());
            requestMessages.add(assistanceMessage);
            bsinCacheProvider.setListEx(chatGPTConfiguration.getUserId() + "ChatCompletionContext", requestMessages, chatGPTConfiguration.getContextExpire());
            System.out.println("chatGPT response: " + assistanceMessage.toString());
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
